package com.itliang.web.service;

import com.itliang.constant.Constants;
import com.itliang.core.model.dto.system.sysuser.SysUserLoginRequest;
import com.itliang.core.redis.RedisCache;
import com.itliang.core.result.BaseResponse;
import com.itliang.core.result.CodeEnum;
import com.itliang.core.result.ResponseCode;
import com.itliang.core.result.ResultUtils;
import com.itliang.exception.BusinessException;
import com.itliang.manager.AsyncManager;
import com.itliang.manager.factory.AsyncFactory;
import com.itliang.security.custom.CustomUser;
import com.itliang.utils.JwtUtils;
import com.itliang.utils.StringUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.itliang.constant.RedisConstants.LOGIN_TOKEN_KEY;
import static com.itliang.constant.RedisConstants.LOGIN_TOKEN_TTL;


/**
 * 登录校验方法
 *
 * @author : liangzhuoyuan
 */
@Component
public class LoginService {

    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private RedisCache redisCache;


    public BaseResponse<Map> login(SysUserLoginRequest user) {

        // 登录前的校验
        loginPreCheck(user);
        String account = user.getUserAccount();

        Authentication authenticate = null;
        try {
            Authentication authenticationToken =
                    new UsernamePasswordAuthenticationToken(user.getUserAccount(), user.getUserPassword());
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authenticate = authenticationManager.authenticate(authenticationToken);
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                AsyncManager.me().execute(AsyncFactory.recordLoginInfo(account, Constants.LOGIN_FAIL, "账号或密码错误"));
                throw new BusinessException(CodeEnum.ACCOUNT_PASSWORD_ERROR);
            } else {
                AsyncManager.me().execute(AsyncFactory.recordLoginInfo(account, Constants.LOGIN_FAIL, e.getMessage()));
                throw new BusinessException(ResponseCode.LOGIN_FAIL, e.getMessage());
            }
        }

        // 记录登录成功日志
        AsyncManager.me().execute(AsyncFactory.recordLoginInfo(account, Constants.LOGIN_SUCCESS, "登录成功"));

        CustomUser customUser = (CustomUser) authenticate.getPrincipal();
        Long userId = customUser.getSysUser().getId();
        // 生成token
        String token = JwtUtils.createToken(userId, account);

        //保存token到redis
        String tokenKey = LOGIN_TOKEN_KEY + customUser.getUsername();
        redisCache.setCacheObject(tokenKey, token, LOGIN_TOKEN_TTL, TimeUnit.SECONDS);

        Map<String, Object> map = new HashMap<>();
        map.put(Constants.TOKEN, token);

        return ResultUtils.success(map);
    }

    /**
     * 登录前的校验
     *
     * @param user 登录的用户信息
     */
    public void loginPreCheck(SysUserLoginRequest user) {
        String account = user.getUserAccount();
        String password = user.getUserPassword();
        if (StringUtils.isEmpty(account) || StringUtils.isEmpty(password)) {
            AsyncManager.me().execute(AsyncFactory.recordLoginInfo(account, Constants.LOGIN_FAIL, "请求参数错误"));
            throw new BusinessException(CodeEnum.PARAMS_ERROR);
        }
    }
}
